package m.server.web;

import com.alibaba.fastjson.JSONObject;
import m.server.ReadBody;
import m.server.web.req.*;
import m.server.web.res.StatusCode;
import m.system.util.ActionUtil;
import m.system.util.SystemUtil;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class Request {
    private final ReadBody readBody;
    private final HttpMethod method;
    private final String uri;
    private final String protocol;
    private final String ipAddress;
    private final String contentType;
    private final Map<Header,String> header;
    private final Map<String,Cookie> cookies;
    private boolean isReadBody=false;
    private final JSONObject params;
    private List<FormData> formDataList;
    private byte[] contentBytes;
    private boolean enableUrl=false;

    public void destroy() {
        if(null!=formDataList&&!formDataList.isEmpty()){
            for(FormData fd : formDataList) fd.destroy();
        }
        formDataList=null;
    }
    private HttpMethod getMethod(int n) throws IOException {
        if(n>1000){
            SystemUtil.printErr("无法读取http内容");
            throw new RequestExecption(StatusCode.None);
        }
        String m=new String(readBody.readNext(ReadBody.EmptyByte));
        HttpMethod hm=HttpMethod.to(m);
        if(null==hm){
            try {
                Thread.sleep(1);
            } catch (InterruptedException ignored) {}
            return getMethod(n+1);
        }else{
            return hm;
        }
    }
    public Request(ReadBody rb,String ipAddress) throws IOException {
        readBody=rb;
        this.method=getMethod(0);
        String uri=new String(readBody.readNext(ReadBody.EmptyByte));
        this.params=new JSONObject();
        if(uri.contains("?")){//解析url参数
            int idx=uri.indexOf("?");
            this.uri=uri.substring(0,idx);
            this.params.putAll(urlParamToJSON(uri.substring(idx+1)));
        }else{
            this.uri=uri;
        }
        this.protocol=new String(readBody.readNext(ReadBody.NewLine));
        header=new HashMap<>();
        cookies=new HashMap<>();
        byte[] head;
        while((head=readBody.readNext(ReadBody.NewLine)).length>0){
            String line=new String(head);
            int n=line.indexOf(":");
            if(n>0) {
                Header h=Header.to(line.substring(0, n));
                String v=line.substring(n + 1).trim();
                header.put(h, v);
//                System.out.println(line);
                if(h==Header.Cookie){
                    for(String cs : v.split(";")){
                        int i=cs.indexOf("=");
                        if(i>0){
                            String k=cs.substring(0,i).trim();
                            cookies.put(k,new Cookie(k,cs.substring(i+1).trim()));
                        }
                    }
                }
            }
        }
        this.ipAddress=getHeader(Header.XForwardedFor,ipAddress);
        this.contentType=getHeader(Header.ContentType,"");
        if(ContentType.FORM_DATA.is(contentType)&&!ActionUtil.isFormData(this.uri)){
        }else {
            readBody();
        }
    }
    private void readBody() {
        if(!this.isReadBody){
            int cl=Integer.parseInt(getHeader(Header.ContentLength,"0"));
            if(cl==0){
                this.isReadBody=true;
                return;
            }
            if(cl>100*1024*1024) throw new RequestExecption(StatusCode.BadGateway,"请求数据过大");
            try {
                if(ContentType.JSON.is(contentType)){
                    this.params.putAll((JSONObject)JSONObject.parse(new String(readBody.readAllByte(cl))));
                }else if(ContentType.URLENCODED.is(contentType)){
                    this.params.putAll(urlParamToJSON(new String(readBody.readAllByte(cl))));
                }else if(ContentType.FORM_DATA.is(contentType)){
                    String boundary=contentType.split(";")[1].split("=")[1];
                    this.formDataList=readBody.readFormData(cl,boundary);
                }else{
                    contentBytes=readBody.readAllByte(cl);
                }
                this.isReadBody = true;
            }catch (Exception e){
                SystemUtil.println("读取body异常：",e.getMessage());
                e.printStackTrace();
                throw new RequestExecption(StatusCode.BadGateway,"网络异常");
            }
        }
    }
    /**
     * url?后面字符串转json  后续：增加.转对象
     */
    protected static JSONObject urlParamToJSON(String urlParam) {
        JSONObject json=new JSONObject();
        String[] ps=urlParam.split("&");
        for(String p : ps){
            int i=p.indexOf("=");
            if(i>-1) {
                ActionUtil.fillJSONObject(json, decode(p.substring(0, i)), decode(p.substring(i + 1)));
            }else{
                ActionUtil.fillJSONObject(json, decode(p),"");
            }
        }
        return json;
    }
    protected static String decode(String str){
        try {
            return URLDecoder.decode(str,"UTF-8");
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException(e);
        }
    }

    public boolean isEnableUrl() {
        return enableUrl;
    }

    public void setEnableUrl(boolean enableUrl) {
        this.enableUrl = enableUrl;
    }

    /**
     * 获取header
     */
    public String getHeader(Header key){
        return header.get(key);
    }

    /**
     * 获取header值 不存在则返回defaultValue
     */
    public String getHeader(Header key,String defaultValue){
        String v=getHeader(key);
        if(null==v) return defaultValue;
        else return v;
    }

    /**
     * 设置header值
     */
    public void setHeader(Header key,String value){
        header.put(key,value);
    }

    /**
     * 获取cookie
     */
    public Cookie getCookie(String key){
        return cookies.get(key);
    }
    /**
     * 获取请求方法
     */
    public HttpMethod getMethod() {
        return method;
    }

    /**
     * 获取uri
     */
    public String getUri() {
        return uri;
    }

    /**
     * 获取http协议
     */
    public String getProtocol() {
        return protocol;
    }
    /**
     * 获取ip地址
     */
    public String getIpAddress() {
        return this.ipAddress;
    }

    /**
     * 获取所有参数
     */
    public JSONObject getRequestJson(){
        return this.params;
    }

    /**
     * 获取FormData数据
     */
    public List<FormData> getFormDatas() {
        return formDataList;
    }

    /**
     * 获取请求类型
     */
    public String getContentType() {
        return contentType;
    }

    /**ContentType不为( application/json , application/x-www-form-urlencoded , multipart/form-data )
     * 获取body所有的byte
     */
    public byte[] getContentBytes() {
        return contentBytes;
    }
}
